/*
 * @(#)EmailMessageSenderComparator.java
 *
 * Copyright (c) 2004 DCIVision Ltd
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of DCIVision
 * Ltd ("Confidential Information").  You shall not disclose such Confidential
 * Information and shall use it only in accordance with the terms of the license
 * agreement you entered into with DCIVision Ltd.
 */

package com.dcivision.upgrade;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.dcivision.framework.GlobalConstant;
import com.dcivision.framework.SessionContainer;
import com.dcivision.upgrade.handler.UpgradeHandler;

import uk.ltd.getahead.dwr.ExecutionContext;

/**
 * A service to process upgrade request from Ajax (DWR) client. Starting a
 * upgrade via method {@link #operateUpgrade(String)}, this method will start a
 * separate thread to do the upgrade, and return some flag to client if upgrade
 * thread launches successfully.
 * 
 * You can tracking the upgrade and fetch the upgrade progress state via method
 * {@link #getUpgradeProgressReport()} after a upgrade is started.
 * 
 * @author      Brook.Huang
 * @company     DCIVision Limited
 * @creation    19/04/2007
 * @version     $Revision: 1.5 $
 */
public final class UpgradeAjaxProcessor {

  private static final Log LOG = LogFactory.getLog(UpgradeAjaxProcessor.class);

  /** Identifies upgrade report not found flag */
  public static final String UP_RP_NONE = "404";

  /** Identifies upgrade is processiong */
  public static final String UP_RP_PROCESSIONG = "300";

  /** Identifies upgrade have errors occur flag */
  public static final String UP_RP_ERRORS_OCCUR = "505";

  /** Identifies upgrade have completed successfully flag */
  public static final String UP_RP_OK = "200";

  public static final String UPGRADE_STATE_KEY = "UPGRADE_STATE";

  public static final String UPGRADE_STATE_FLAG_KEY = "UPGRADE_STATE_FLAG";

  public UpgradeAjaxProcessor() {
    // Make sure that upgrade state flag is existed.
    if (ExecutionContext.get().getServletContext().getAttribute(UPGRADE_STATE_FLAG_KEY) == null) {
      ExecutionContext.get().getServletContext().setAttribute(UPGRADE_STATE_FLAG_KEY, UP_RP_NONE);
    }
  }

  /**
   * Upgrade entrance for Ajax client. This metod will launch a separate
   * thread to do the upgrade.
   */
  public synchronized String operateUpgrade(StandardUpgradeRequest upgradeRequest) {
    String report = null;

    String upgradeStateFlag = (String) ExecutionContext.get().getServletContext().getAttribute(UPGRADE_STATE_FLAG_KEY);

    if (!UP_RP_NONE.equals(upgradeStateFlag)) {
      report = "Another upgrade request is processing!";
      return (report);
    }

    final UpgradeHandler handler;

    try {

      // Attach SessionContainer which contains the request principal as request parameter.
      upgradeRequest.setUpgradeParameter(GlobalConstant.SESSION_CONTAINER_KEY, getSessionContainer());

      handler = UpgradeManager.getHandlerFor319To320(upgradeRequest);
    } catch (Exception e) {
      LOG.fatal("Upgrade initialize faild!", e);
      report = "Start upgrade faild, errors occur at upgrade initialize. \n" + "Errors message : " + e.getMessage();
      return (report);
    }

    if (handler != null) {

      new Thread("Upgrade Thread") {
        public void run() {
          try {
            handler.upgrade();
          } catch (Exception e) {
            LOG.fatal("Upgrade faild!", e);
          }
        }
      }.start();

      ExecutionContext.get().getServletContext().setAttribute(UPGRADE_STATE_KEY, handler.getUpgradeState());
      ExecutionContext.get().getServletContext().setAttribute(UPGRADE_STATE_FLAG_KEY, UP_RP_PROCESSIONG);

      report = UP_RP_PROCESSIONG;
    }

    return (report);
  }

  /**
   * Calls this method to tracking the upgrade.
   * 
   * <pre>
   * The returned flag means:
   * <li>{@link #UP_RP_NONE} means there is none of upgrade running in servers now.
   * <li>{@link #UP_RP_ERRORS_OCCUR} means there are error(s) occur during the upgrade.
   * <li>{@link #UP_RP_OK} means current upgrade have been completed successfully.
   * <li>Other text is the report of current upgrade.
   * </pre>
   * 
   */
  public String getUpgradeProgressReport() {
    String progressReport = null;

    String upgradeStateFlag = (String) ExecutionContext.get().getServletContext().getAttribute(UPGRADE_STATE_FLAG_KEY);
    UpgradeState upgradeState = (UpgradeState) ExecutionContext.get().getServletContext().getAttribute(UPGRADE_STATE_KEY);

    if (UP_RP_NONE.equals(upgradeStateFlag)) {
      progressReport = upgradeStateFlag;
    } else if (UP_RP_OK.equals(upgradeStateFlag) || UP_RP_ERRORS_OCCUR.equals(upgradeStateFlag)) { // Reset the upgrade enviroment after upgrade completed.
      ExecutionContext.get().getServletContext().setAttribute(UPGRADE_STATE_KEY, null);
      ExecutionContext.get().getServletContext().setAttribute(UPGRADE_STATE_FLAG_KEY, null);

      progressReport = upgradeStateFlag;
    } else if (UP_RP_PROCESSIONG.equals(upgradeStateFlag)) {
      progressReport = upgradeState.getProgressReport();

      if (upgradeState.isUpgradeCompleted()) {
        if (upgradeState.isExceptionOccur()) {
          ExecutionContext.get().getServletContext().setAttribute(UPGRADE_STATE_FLAG_KEY, UP_RP_ERRORS_OCCUR);
        } else {
          ExecutionContext.get().getServletContext().setAttribute(UPGRADE_STATE_FLAG_KEY, UP_RP_OK);
        }
      }
    }

    return (progressReport);
  }

  private SessionContainer getSessionContainer() {
    SessionContainer ctx = (SessionContainer) ExecutionContext.get().getSession().getAttribute(GlobalConstant.SESSION_CONTAINER_KEY);
    if (ctx == null) {
      ctx = new SessionContainer();
      ExecutionContext.get().getSession().setAttribute(GlobalConstant.SESSION_CONTAINER_KEY, ctx);
    }
    return (ctx);
  }

}
